package com.siashan.toolkit.sms.provider;

import com.alibaba.fastjson.JSON;
import com.siashan.toolkit.sms.aliyun.AliyunSmsConfig;
import com.siashan.toolkit.sms.aliyun.AliyunSmsSendExecutor;
import com.siashan.toolkit.sms.baiducloud.core.BaiduCloudSmsConfig;
import com.siashan.toolkit.sms.baiducloud.core.BaiduCloudSmsSendExecutor;
import com.siashan.toolkit.sms.cache.SmsCacheTemplate;
import com.siashan.toolkit.sms.chinamobile.core.ChinaMobileSmsConfig;
import com.siashan.toolkit.sms.chinamobile.core.ChinaMobileSmsSendExecutor;
import com.siashan.toolkit.sms.core.entity.*;
import com.siashan.toolkit.sms.core.exception.Unisms4jException;
import com.siashan.toolkit.sms.core.executor.SmsSendExecutor;
import com.siashan.toolkit.sms.core.utils.StringUtils;
import com.siashan.toolkit.sms.huaweicloud.core.HuaWeiCloudSmsConfig;
import com.siashan.toolkit.sms.huaweicloud.core.HuaWeiCloudSmsSendExecutor;
import com.siashan.toolkit.sms.jdcloud.core.JdCloudSmsConfig;
import com.siashan.toolkit.sms.jdcloud.core.JdCloudSmsSendExecutor;
import com.siashan.toolkit.sms.qiniu.core.QiniuSmsConfig;
import com.siashan.toolkit.sms.qiniu.core.QiniuSmsSendExecutor;
import com.siashan.toolkit.sms.yunpian.core.YunpianSmsConfig;
import com.siashan.toolkit.sms.yunpian.core.YunpianSmsSendExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * 短信服务商
 *
 * @author siashan
 * @since v1.1.8
 **/
@Slf4j
@Component
public class SmsSendProvider {


    @Autowired
    private SmsCacheTemplate smsCacheTemplate;

    /**
     * 短信发送执行器池
     */
    private static ArrayList<SmsSendExecutor> executorPool = new ArrayList<>();

    /**
     * 白名单
     */
    private SmsWhiteList whiteList = null;

    /**
     * 短信发送频率限制
     */
    private SmsFrequencyLimitConfig frequencyLimit = null;


    /**
     * 初始化短信渠道
     *
     * @param channelList 短信渠道列表
     */
    public void init(List<SmsProviderChannel> channelList) {
        executorPool.clear();
        if (null != channelList && !channelList.isEmpty()) {
            for (SmsProviderChannel channel : channelList) {
                SmsSendExecutor executor = null;
                SmsChannel smsChannel = channel.getChannel();
                switch (smsChannel) {
                    case QINIU:
                        QiniuSmsConfig qiniuSmsConfig = JSON.parseObject(channel.getConfig(), QiniuSmsConfig.class);
                        executor = new QiniuSmsSendExecutor(qiniuSmsConfig, channel.getTemplateMap());
                        break;
                    case ALIYUN:
                        AliyunSmsConfig aliyunSmsConfig = JSON.parseObject(channel.getConfig(), AliyunSmsConfig.class);
                        executor = new AliyunSmsSendExecutor(aliyunSmsConfig, channel.getTemplateMap());
                        break;
                    case YUNPIAN:
                        YunpianSmsConfig yunpianSmsConfig = JSON.parseObject(channel.getConfig(), YunpianSmsConfig.class);
                        executor = new YunpianSmsSendExecutor(yunpianSmsConfig, channel.getTemplateMap());
                        break;
                    case CHINAMOBILE:
                        ChinaMobileSmsConfig chinaMobileSmsConfig = JSON.parseObject(channel.getConfig(), ChinaMobileSmsConfig.class);
                        executor = new ChinaMobileSmsSendExecutor(chinaMobileSmsConfig, channel.getTemplateMap());
                        break;
                    case JD:
                        JdCloudSmsConfig jdCloudSmsConfig = JSON.parseObject(channel.getConfig(), JdCloudSmsConfig.class);
                        executor = new JdCloudSmsSendExecutor(jdCloudSmsConfig, channel.getTemplateMap());
                        break;
                    case BAIDU:
                        BaiduCloudSmsConfig baiduCloudSmsConfig = JSON.parseObject(channel.getConfig(), BaiduCloudSmsConfig.class);
                        executor = new BaiduCloudSmsSendExecutor(baiduCloudSmsConfig, channel.getTemplateMap());
                        break;
                    case HUAWEI:
                        HuaWeiCloudSmsConfig huaWeiCloudSmsConfig = JSON.parseObject(channel.getConfig(), HuaWeiCloudSmsConfig.class);
                        executor = new HuaWeiCloudSmsSendExecutor(huaWeiCloudSmsConfig, channel.getTemplateMap());
                        break;
                    default:
                        break;
                }
                if (null != executor) {
                    executor.setChannelCode(channel.getChannelCode());
                    executorPool.add(executor);
                }
            }
        }
    }

    public void initFrequencyLimit(SmsFrequencyLimitConfig frequencyLimit) {
        this.frequencyLimit = frequencyLimit;
    }

    public void initWhiteList(SmsWhiteList whiteList) {
        this.whiteList = whiteList;
    }


    /**
     * 发送短信
     *
     * @param model 参数
     * @param phone 手机号
     */
    public SmsSendResult send(SmsModel model, String phone) {
        return send(getExecutor(),model,Arrays.asList(phone));
    }

    /**
     * 发送短信
     *
     * @param model 参数
     * @param phone 手机号
     * @param channelCode 渠道编码
     */
    public SmsSendResult send(SmsModel model, String phone,String channelCode) {
        return send(getExecutor(channelCode),model, Arrays.asList(phone));
    }

    /**
     * 发送短信
     *
     * @param model  参数
     * @param phones 手机号
     */
    public SmsSendResult send(SmsModel model, Collection<String> phones) {
        return send(getExecutor(),model,phones);
    }

    /**
     * 发送短信
     *
     * @param model  参数
     * @param phones 手机号
     */
    private SmsSendResult send(SmsSendExecutor smsSendExecutor,SmsModel model, Collection<String> phones) {
        boolean send = smsSendExecutor.send(model, phones);
        return SmsSendResult.sendResult(send);
    }

    /**
     * 发送短信
     *
     * @param model  参数
     * @param phones 手机号
     */
    public SmsSendResult send(SmsModel model, Collection<String> phones,String channelCode) {
        SmsSendExecutor smsSendExecutor = getExecutor(channelCode);
        boolean send = smsSendExecutor.send(model, phones);
        return SmsSendResult.sendResult(send);
    }

    /**
     * 发送短信
     *
     * @param model 参数
     * @param phone 手机号
     */
    public SmsSendResult send(SmsVerifyModel model, String phone) {
      return send(getExecutor(),model,phone);

    }

    /**
     * 发送短信
     *
     * @param model 参数
     * @param phone 手机号
     * @param channelCode 渠道编码
     */
    public SmsSendResult send(SmsVerifyModel model, String phone,String channelCode) {
        return send(getExecutor(channelCode),model,phone);
    }

    /**
     * 发送短信
     *
     * @param model 参数
     * @param phone 手机号
     */
    public SmsSendResult send(SmsSendExecutor smsSendExecutor,SmsVerifyModel model, String phone) {
        SmsSendResult sendResult = null;
        SmsFrequencyResult smsFrequencyResult = smsCacheTemplate.preCheck(model, phone, frequencyLimit, whiteList);
        if (smsFrequencyResult.canSend()) {
            boolean send = smsSendExecutor.send(model, phone);
//            boolean send = true;
            if (send) {
                smsCacheTemplate.put(phone, model.getSmsCode(), model.getExpireTimeout());
            }
            sendResult = SmsSendResult.sendResult(send);
        } else {
            sendResult = SmsSendResult.frequnecyCheckFail(smsFrequencyResult);
        }
        return sendResult;

    }

    /**
     * 发送短信
     *
     * @param model         参数
     * @param phone         手机号
     * @param smsCode       短信验证码
     * @param expireTimeout 验证码过期时间
     */
    public SmsSendResult send(SmsVerifyModel model, String phone, String smsCode, Long expireTimeout) {
        model.setSmsCode(smsCode);
        model.setExpireTimeout(expireTimeout);
        return send(getExecutor(),model,phone);
    }

    /**
     * 发送短信
     *
     * @param model         参数
     * @param phone         手机号
     * @param smsCode       短信验证码
     * @param expireTimeout 验证码过期时间
     * @param channelCode 渠道编码
     */
    public SmsSendResult send(SmsVerifyModel model, String phone, String smsCode, Long expireTimeout,String channelCode) {
        model.setSmsCode(smsCode);
        model.setExpireTimeout(expireTimeout);
        return send(getExecutor(channelCode),model,phone);
    }

    /**
     * 校验短信验证码
     *
     * @param phone   手机号
     * @param smsCode 验证码
     * @return SmsVerifyCkResult
     */
    public SmsVerifyCheckResult validate(String phone, String smsCode) {
        String sv = smsCacheTemplate.get(phone);
        smsCacheTemplate.release(phone);
        if (null == sv || "".equals(sv.trim())) {
            return SmsVerifyCheckResult.empty();
        }
        if (sv.equalsIgnoreCase(smsCode)) {
            return SmsVerifyCheckResult.success();
        } else {
            return SmsVerifyCheckResult.fail();
        }
    }


    /**
     * 获取发送渠道
     *
     * @return 发送渠道
     */
    private SmsSendExecutor getExecutor() {
        int size = executorPool.size();
        SmsSendExecutor smsSendExecutor;
        if (size < 1) {
            throw new Unisms4jException("短信发送失败：无可用的短信渠道");
        }
        if (size == 1) {
            smsSendExecutor = executorPool.get(0);
        } else {
            Random random = new Random();
            int n = random.nextInt(size);
            smsSendExecutor = executorPool.get(n);
        }
        return smsSendExecutor;
    }

    /**
     * 获取发送渠道
     *
     * @return 发送渠道
     */
    private SmsSendExecutor getExecutor(String channelCode) {
        if (StringUtils.isNotBlank(channelCode)) {
            int size = executorPool.size();
            SmsSendExecutor smsSendExecutor = null;
            if (size > 0) {
                for (SmsSendExecutor executor : executorPool) {
                    if (executor.getChannelCode().equals(channelCode)) {
                        smsSendExecutor = executor;
                        break;
                    }
                }
            }
            if (null == smsSendExecutor) {
                throw new Unisms4jException("短信发送失败：无可用的短信渠道");
            }
            return smsSendExecutor;
        } else {
            return getExecutor();
        }
    }


}
